/** @jsxImportSource @emotion/react */
import * as React from "react";

/**结论区域只有唯一一个的；但是允许自己拆分为多个的可输入的字段名的区域。
 * 一个路由标签sno可以路由到多个的RecordInputConfig对应视图的。
 * 【兼容性】 其它类型的报告可能直接采用本配置方式的类型定义系统和函数。
 * */
export interface EvaluateItemConfig {
    //大项目号
    x: string;
    //主体的项目编码串；
    y: string;
    //可拆分的项目的 name:实际是结论字段的标签 + cfname[]分别存储； 【正式报告可能会】再一次汇总映射的？？就算走cfname的但是name也必须有(存放其它_D_M_S_Z字段)。
    name: string;
    /**正式报告的 标题位置文本
     * */
    titl: string | React.ReactNode;
    //【类型检查还是非常重要的】实际数据desc: 字段配置了[,]数组形式的DOM[1,2];导致的报错：【还死活找不到】具体的代码出处。typescript检查被:as xxx忽视掉。 as RecordIspArea
    desc: string | React.ReactNode;

    iclas?: string;  //项目x.y.z 后面的类别
    pre?: string;    //项目x.y.z 前面的文字

    //最大支持两个级别的 标题：
    //最大一级的项目标题：：按照顺序后面没配置的就合并进Cell中。同时考虑seco参数。
    //【差别】大标题不支持跨越编辑器的继承;
    big?: string;
    //最大一级级别栏目的Span； 没配置的没有该 <td>; 同时附加seco的就会有2个列。
    bspan?: number;
    //第二级别 项目字段的标题，标题如果被配置上了的：那么正式报告这个项目位置必须支持拆分（大的套住小的列的拆分）：大列拆了 小的列跟着拆分。。
    //【可利用】''和undefined的不同来做配置，适应特殊情形。
    seco?: string;
    //第二级别{title}栏目的Span； 没配置的没有该 <td>; 若seco没有配置的就没有第二级的栏目，这样的话只有一个列。
    //可以设置tspan=1让第二栏目的span强制设为一行的，独立于rspan的数字。
    tspan?: number;
    /**有配置才有录入：存储名字用本项目 给分:+"_F"来保存；  计算 汇总：
     * 【约束前提】权重评价涵盖的全部项目都 只能在同一个大编辑区底下 ，按照编辑区项目顺序，没配置的都归入顺序下面有配置的哪一个项目所囊括。
     * 多个权重和==1.21； 单项最高给分=80；  囊括三个项目区15-17	聚合给权重和录入分数； 权重数要依照正式报告的数据为准;
     * 若weight是字符串类型的：表明权重跨越行数太多了，string用来替代该位置的说明，同一个权重可以被分解到了多个的编辑区域，避免语义混淆，计算权重时刻忽略掉这个配置。
     * */
    weight?: number | string;
    //权重输入的提示词； 默认， 编码范围 -。【结果】汇总栏目的录入 显示标题；
    //可能在原始记录中代替项目区的第二栏项目列的描述。 【出现】tips字段发挥两个作用，编辑和记录两地方显示不可协调了；【若想解决】只能增加新的参数配置。保障那个正确优先的/记录。
    tips?: string;
    //得分  score?: number;
    //权重+得分栏目的Span； 没配置的没有该 <td>
    rspan?: number;
}

/**独立路由的关联对应编辑视图 区块：每次添加最小项目的区域；
 * 整个isp项目的全列表:是RecordIspArea[]；
 * */
export interface RecordEvalArea {
    //独立路由器对应的 编辑区域所映射的区域  tag==Action；
    //这里tag最好不一定就是x.y.z什么的，版本交替会有差异的。
    tag:string;
    //区块编辑器 标记用的
    name:string;
    //可以合并显示多个项目的编辑器等的记录； 【前提条件】必须按照数字大小顺序排序。可允许一次性路由到多个的分最底层的支项目。
    //同一个路由区块内的编辑区域：  多个项目聚合， 有些相同的可免去配置或者免于标题做显示。
    items: EvaluateItemConfig[];
}

/**配置帮助函数
 * 允许weight ='说明文字'
 * 若有配置tips?: string, rspan?:影响原始记录第二栏目，但是正式报告不会改变第二栏目。 tips用于得分提示描述。
 * 把seco?: string设置=''使得记录输出会直接合并第二列。
 * */
export function crtIofEval(name: string,x:string|number,y:string|number, titl: string | React.ReactNode,desc: string | React.ReactNode, iclas?:string, pre?:string,
                            big?: string,bspan?: number, seco?: string,tspan?: number, tips?: string, rspan?: number, weight?: number|string): EvaluateItemConfig {
    return {name, x, y, titl, desc, iclas, pre, big, bspan, seco, tspan, weight, rspan, tips} as EvaluateItemConfig;
}

export function pushEvals(ari: RecordEvalArea[],tag:string,items: EvaluateItemConfig[],name:string): RecordEvalArea[] {
    ari.push({ tag, items, name});
    return ari;
}

/**评估 ：根据 录入的检测结果 严重程度 风险频率 来生成的 风险类别 "A","B","C","D","E","F"
 * 返回：fxclass=风险类别 ；chendu: 严重程度, pinglv:风险频率
 **/
export const itemFenXianClassTransform = (itRes: any,name: string) => {
    let result='／';
    const value= itRes[name];
    let frq= itRes[name+'_P'];
    let ced= itRes[name+'_C'] as number;        //严重程度
    if(!value || value==='' || value==='△'){
        return {chendu: ced, pinglv: frq, fxclass: '' };
    }
    else if(value==='／'){
        return {chendu: ced, pinglv: frq, fxclass: '／' };
    }
    // 'IV' 'Ⅲ' 'Ⅱ' 'Ⅰ'
    if(frq==='A'){
        if(ced<=3)   result='Ⅰ';            //严重程度
        else    result='Ⅱ';
    }
    else if(frq==='B'){
        if(ced<=3)   result='Ⅰ';
        else    result='Ⅱ';
    }
    else if(frq==='C'){
        if(ced<=2)   result='Ⅰ';
        else    result='Ⅱ';
    }
    else if(frq==='D'){
        if(ced<=1)   result='Ⅰ';
        else if(ced<=3)   result='Ⅱ';
        else    result='Ⅲ';
    }
    else if(frq==='E'){
        if(ced<=2)   result='Ⅱ';
        else if(ced<=3)   result='Ⅲ';
        else    result='IV';
    }
    else{
        if(ced<=1)   result='Ⅱ';
        else if(ced<=2)   result='Ⅲ';
        else    result='IV';
    }
    if(value==='√' || value==='▽'){
        if(!frq && !ced){
            ced=3;
            frq='E';
            result='Ⅲ';
        }
    }
    return  {chendu: ced, pinglv: frq, fxclass: result };
}

/**翻译 结果： 符合  不符合
 **/
export const itemCheckResTransform = (itRes: any,name: string) => {
    let result='符合';
    const value= itRes[name];
    if(!value || value==='' || value==='△'){
        return '不符合';
    }
    else if(value==='／'){
        return '／';
    }
    else if(value==='×'){
        return '不符合';
    }
    else return result;
}

/**原始记录 就需要转换结果的： 若是正式报告的转换可能牵涉分项目的合并的意思。
 * action导航的每个配置项目区域：必须能够决定结论。【注意】不能跨区配置。
 * @return 单一一个项目{正式报告对应一个项目序号的； 原始记录也是关联着项目顺序表上最左边的序号}的 自动综合出来的判别结果。
 * @param itRes : 原始记录 或者 对于正式报告有些可能被转换后的。
 * 默认值 从'合格' 改成 '/'
 **/
export const itemResTransformEval = (itRes: any,config: EvaluateItemConfig) => {
    let result='／';
    //一对一的情况 项目栏目的x .y .z 都是单独区分的话；
    const jilu= itRes[config.name];
    if(!jilu || jilu==='' || jilu==='×' || jilu==='△' ){
        result='不合格';
    }
    else if(jilu==='√' || jilu==='▽'){
        result='合格';
    }
    else if(jilu==='／'){
    }
    else
        throw new Error(`结论非法${jilu}`);
    return  result;
}

/**机电检验项目列表情形，寻找不合格项目的全貌：x.y.z iClass 原因。 自拆分项目 多个子项目有独立的原因字段情况，简单合并不合格原因说明。
 * 而且：若是自拆分项目的，多个子项目需要合并不合格内容。
 * 依据记录来初始化 检验不合格项目[] ,
 * @param ItemArs 全体项目配置
 * @param options { noCB : 有些项目编码重复的需要额外做区分；  clsSplit?: 是否需要按照iClass拆分三个不合格目标表的。
 *  iClass?:  只针对单独一个类别iClass处理的。
 *  classes? 所有有效类别，按照类别= A,B,undefined, 用于检查配置异常：对于clsSplit=true才有意义的。
 * }
 * 剔除不合格后端对象存储t:area.tag的要求，改为动态生成，破除依赖性，增强强强壮性，保证版本旧数据迁移升级无忧。
 * @return 直接给不合格列表用的对象
 * */
export const itemResultUnqualifiedEvaluate =(orc: any, ItemArs:RecordEvalArea[],
                      options:{
                        noCB?: (no:string,et:EvaluateItemConfig)=>string,
                        clsSplit?: boolean,    //需要按照iClass拆分三个不合格目标表的。
                        iClass?: string,
                        classes?: (string|undefined)[],     //合法的类别有那些 undefined若有的，那么需要放在第一个位置.classes[0]的。
                      }
) => {
    let failure: any[]=[];          //存储的是 标签 no:? 项目URL定位？ key还需要用于获取结果对象。
    let seq = 0;
    let ox: string;
    let oy: string;
    ItemArs?.forEach((area, b) => {
        //列跨 span X.y的X列这里就不要跨越area范围了；以一个tag对应的area.items最大搜索区域来决定各个列span;当前已经为x,y,z,t分配的具体行数多少。
        //配置已经敲定了有几行， td跨越几行 【前提】假设：一个结论对照这里一个items[?]; 随后一一对应一个不合格项目。
        area && area.items.forEach((et:EvaluateItemConfig, n:number) => {
            if(et){
                if(options.clsSplit && options.classes){
                    if(!options.classes.find(c=>c===et.iclas)){
                        //第一个是 undefined特殊转换。.classes.find（）没法处理undefined的特例，再次补充判别；
                         if(options.classes[0]!==et.iclas)
                                throw new Error(`非法iClass设置x:`+et.x+",y:"+et.y);
                    }
                }
                if(!options.clsSplit || (options.clsSplit && et.iclas===options.iClass) ){
                    seq += 1;
                    let nowColumns;    //有几列， 得依据范围内的全部项目来判定各个列到底会跨越几行的（自拆分项目会有多方=行的），x.y.z.t分别决定。
                    if(et.y) nowColumns=2;
                    else if(et.x) nowColumns=1;
                    else throw new Error(`非法列设置u`+et.y);
                    ox=et.x??ox;
                    oy=et.y??oy;
                    let stno= 1===nowColumns? `${ox}` : `${ox}.${oy}` ;
                    stno=et.pre? (et.pre+stno): stno;     //URL上面的文本支持pre?吗 格式
                    //【自拆分项目】必须在同一个区块都配置上；不能跨越２个编辑区。
                    let res=itemResTransformEval(orc, et);
                    if(res==='不合格'){
                        //【例外情况的】回调处理函数；stno特殊转换。 (stno，et:RecordInputConfig）=？ 如何从 stno关联到 t:area.tag
                        stno=options.noCB? options.noCB!(stno, et) : stno;
                        //c:类别字段（若按照iClass拆分就不用保存后端）， p：附带项目编码前缀。
                        if(options.clsSplit)
                            failure.push({no:stno, b: orc[et.name+'_D']});
                        else
                            failure.push({no:stno, c:et.iclas, b: orc[et.name+'_D']});
                    }
                }
            }
        });
    });
    // if(特殊替换)  特殊替换(orc, out);
    //返回  存储数据库的对象{no: ts,c: itRes[ts].iClass, b: itRes[ts].fdesc}; } + 前端的导航点击URL跳转编辑器关联的tag；
    return failure;
}

/**评估：构建允许反方向 搜索tag no的Map对象。
 * @param noCB  特别项目编码的处理回调函数。
 * @param ItemArs  全体检验项目的配置表
 * */
export const useItemsMapEval= ({ ItemArs, noCB }
                               :{ ItemArs:RecordEvalArea[], noCB?:(no:string,et:EvaluateItemConfig)=>string }
) => {
    const itemsMap =React.useMemo(() => {
        const itemsMap = new Map<string,string>();
        let ox: string;
        let oy: string;
        ItemArs?.forEach((area, b) => {
            area && area.items.forEach((et:EvaluateItemConfig, n:number) => {
                if(et){
                    let nowColumns;    //有几列， 得依据范围内的全部项目来判定各个列到底会跨越几行的（自拆分项目会有多方=行的），x.y.z.t分别决定。
                    if(et.y) nowColumns=2;
                    else if(et.x) nowColumns=1;
                    else throw new Error(`非法列设置m`);
                    ox=et.x??ox;
                    oy=et.y??oy;
                    let stno= 1===nowColumns? `${ox}` : `${ox}.${oy}` ;
                    stno=et.pre? (et.pre+stno): stno;     //URL上面的文本支持pre?吗 格式
                    //【例外情况的】回调处理函数；stno特殊转换。 (stno，et:RecordInputConfig）=？ 如何从 stno关联到 t:area.tag
                    stno=noCB? noCB(stno, et) : stno;
                    itemsMap.set(stno, area.tag);
                }
            });
        });
        return  itemsMap;
    }, [ItemArs,noCB]);

    return [itemsMap];
};

